package es.abredatos.energyes

class ChartService {
	
	// Injected by grails
	def grailsApplication
	
	/**
	 * This method returns a list with information about the production
	 * in the year passed as parameter.
	 * 
	 * Each item of the result is a map with this structure:
	 * 
	 * productionInfo = [
	 *		region:Region,
	 *		renewable:XX(int),
	 *		noRenowable:YY(int),
	 *		renewableIndex:x (1-5),
	 *		noRenewableIndex:y (1-5)
	 * ]
	 */
	def findAllProductionInfoByYear(Integer year) {
		def result = []
		def productionItems, productionInfo, energies
		def regions = Region.list()
		
		energies = getEnergyTypes()
		
		regions.each { region ->
			productionInfo = [region:region]
			
			// Renewable
			productionItems = findAllProductionItemsByYearAndInRegionAndInEnergies(year, region, energies[0])
			productionInfo.renewable = productionItems.sum{it.production}
			
			// No renewable
			productionItems = findAllProductionItemsByYearAndInRegionAndInEnergies(year, region, energies[1])
			productionInfo.noRenewable = productionItems.sum{it.production}
			
			result << productionInfo
		}
		
		// Calculating the relative indexes for each data production
		addIndexes(result)
		
		return result
	}

	/**
	 * This method adds the elements renewableIndex and noRenewableIndex to the elements
	 * passed in the list. Each item in this list has two base elements: renewable and noRenewable.
	 */
	private void addIndexes(List productionInfos) {
		List allDataProduction = productionInfos.collect{[it.renewable, it.noRenewable]}.flatten()
		Integer max = allDataProduction.max()
		Integer min = allDataProduction.min()
		Integer range = max - min
		Integer maxRange = grailsApplication.config.energy.imageRange.to
		Integer minRange = grailsApplication.config.energy.imageRange.from
		
		productionInfos.each { productionInfo ->
			productionInfo.renewableIndex = (((productionInfo.renewable - min) / max) * maxRange) + minRange
			productionInfo.noRenewableIndex = (((productionInfo.noRenewable - min) / max) * maxRange) + minRange
			
			productionInfo.renewableIndex = Math.round(productionInfo.renewableIndex) as Integer
			productionInfo.noRenewableIndex = Math.round(productionInfo.noRenewableIndex) as Integer
		}
	}
	
	/**
	 * This method returns a list with all the production items associated with the passed
	 * year, with a province in the passed region and with an energy in the passed list.
	 */
	private List findAllProductionItemsByYearAndInRegionAndInEnergies(Integer year, Region region, List energies) {
		ProductionItem.createCriteria().listDistinct {
			eq('year', year)
			'in'('province', region.provinces)
			'in'('energy', energies)
			
			cache true
		}
	}
	
	/**
	 * @return A list with two items: a list of renewable energies and a list of not renewable energies
	 */
	private List getEnergyTypes() {
		[
			Energy.values().findAll{it.renewable},
			Energy.values().findAll{!it.renewable}
		]
	}
	
	/**
	 * This method returns the pruduccion for an instant in time according to the energy and the selected region
	 * 
	 * @param year
	 * @param month
	 * @param energy, if energy == null => all energies
	 * @param provinces 
	 * @return total production for the selected params
	 */
	def findProductionByInstant(year, month, energy, provinces){
		def totalProduction = 0
		log.debug("findProductionByInstant: year:${year}, month:${month}, energy:${energy}, provinces:${provinces}")
			def c = ProductionItem.createCriteria()
			totalProduction = c.get{
				projections {
					sum "production"
				}
				eq("year",year)
				and{
					eq("month",month)
					if(energy){
						eq("energy",energy)	
					}
					'in'("province",provinces)
				}
			}
			log.debug("Total production for an instant: ${totalProduction}")
		return totalProduction
	}
	
	/**
	 * 
	 * @param yearRange [initYear,endYear]
	 * @param monthRange [initMonht,endMonth]
	 * @param energy type of energy, if energy == null => all
	 * @param provinces list of provinces
	 * @return the list of production value for the chart
	 */
	def returnProductionsToChart(yearRange, monthRange, energy, provinces){
		def initYear = yearRange[0]
		def endYear = yearRange[1]
		def initMonth = monthRange[0]
		def endMonth = monthRange[1]
		def allMonths = grailsApplication.config.energy.data.initLoad.months
		def intervalMonths = []
		def allYears =  [*initYear..endYear]
		def listProductions = []
		log.debug("ReturnProductionsToChart - interval: ${monthRange[0]} ${yearRange[0]} - ${monthRange[1]} ${yearRange[1]}")
		allYears.each{ y -> 
			if(allYears.size() > 1 && y==initYear){
				intervalMonths = allMonths[allMonths.indexOf(initMonth)..11]
				log.debug("Months of the first year: ${intervalMonths}")
			}else if(allYears.size() > 1 && y==endYear){
				intervalMonths = allMonths[0..allMonths.indexOf(endMonth)]
				log.debug("Months of the last year: ${intervalMonths}")
			}else if(allYears.size() == 1){
					intervalMonths = [*initMonth..endMonth] 
			}else intervalMonths=allMonths	
			
			intervalMonths.each { m ->
				listProductions<<findProductionByInstant(y,m,energy,provinces)
			}
		}
		log.debug("List of Productiosn: ${listProductions}")
		return listProductions
	}

}
